package com.hsylient.aop.aspect;

import com.hsylient.aop.annotations.RetryOnException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

/**
 * 使用spring矿建的aop 写了一个后置处理器
 * 主要解决的问题是在方法调用报错的时候实现重试的机制
 *
 */
@Slf4j
@Aspect
@Component
public class RetryAspect {

    @AfterThrowing(value = "@annotation(retryAnnotation)", throwing = "exception")
    public void retryOnException(JoinPoint joinPoint, RetryOnException retryAnnotation, Exception exception) throws Throwable {

        // 这里获取了注解中自定义重试次数
        int maxRetries = retryAnnotation.maxRetries();
        int attempt = 1;

        while (attempt <= maxRetries) {

            // 这里加了try-catch的作用是方法执行有异常就重试，直到达到最大次数才停下来
            try {
                // 打印了方法的签名还有目前已经重试的次数
                log.info("Retrying method: {}, attempt {}", joinPoint.getSignature().getName(), attempt);

                // 这一行代码大概用了反射，让报错的方法再执行一次
                joinPoint.getTarget().getClass().getMethod(
                        joinPoint.getSignature().getName(),
                        ((MethodSignature) joinPoint.getSignature()).getParameterTypes()
                ).invoke(joinPoint.getTarget(), joinPoint.getArgs()); // Retry the method
                return; // If successful, exit the loop
            } catch (Exception e) {
                if (attempt == maxRetries) {
                    System.out.println("Maximum retry attempts reached.");
                    throw exception; // Rethrow the last exception after retries are exhausted
                }
                attempt++;
            }
        }
    }
}
